Chuyển tới nội dung chính
Phiên bản: 8.0.0

Metabox & metadata

SkillDo CMS sở hữu tính năng Metabox mạnh mẽ giúp bạn thêm "Bảng Phụ" để lưu thêm nhiều thông tin dưới dạng Metadata mà KHÔNG CẦN đụng đến Cột (Column) trong Bảng Chính!


1. Hoạt Động (Hook)

SkillDo quy định 2 Action chính để bạn thao tác với giao diện tạo/sửa Bài Viết (hoặc Chủ Đề, Category):

  1. add_meta_box: Action yêu cầu in một vùng HTML Form nằm lọt thỏm trong giao diện chung.
  2. save_{module}_object: Action gọi khi người quản trị Lưu Cập Nhật (cả thêm mới lẫn cập nhật), nhận tham số ($id, $request, $insertData, $dataOutside). Ngoài ra còn có:
    • save_{module}_object_add – chỉ khi thêm mới
    • save_{module}_object_edit – chỉ khi cập nhật
    • save_object – bắt tất cả module, nhận thêm $module ở tham số thứ 2

Bộ thư viện Form Builder (Mảng Array giống Plugin Element) được sử dụng để sinh ra giao diện TextBox / Select / Radio cho Metadata một cách đồng bộ nhất với Admin thay vì bạn phải tự cặm cụi code tay HTML Bootstrap.


2. Nơi Đăng Ký Metabox Trong Theme

Cách tổ chức chuẩn trong theme là:

  • Tạo một class riêngtheme-child/app/Custom/ để đóng gói toàn bộ logic đăng ký + render + lưu.
  • Đăng ký class vào hệ thống tại theme-child/bootstrap/theme-child.php bằng add_action.

3. Bước 1 – Tạo Class Metabox trong theme-child/app/Custom/

Tạo file theme-child/app/Custom/PostSourceMetabox.php:

<?php
namespace Theme\Custom;

use SkillDo\Cms\Metabox\Metabox;
use SkillDo\Cms\Form\Form;
use SkillDo\Http\Request;
use Metadata;

class PostSourceMetabox
{
/**
* Đăng ký metabox vào hệ thống.
* Được gọi qua add_action('add_meta_box', ...) từ bootstrap.
*/
public static function register(): void
{
// Metabox::add($id, $title, $callback, $args = [])
Metabox::add(
'source_post_metabox', // ID Bảng Phụ
'Nguồn Gốc Của Bài Viết Này', // Tiêu đề của Box
[static::class, 'render'], // Hàm callback render form
[
'module' => 'post', // Áp dụng cho module (post, page, products...)
'position' => 10, // Thứ tự sắp xếp hiển thị
'content' => 'leftBottom' // Vị trí (leftBottom | leftTop | right)
]
);
}

/**
* Render nội dung Form trong Box.
* Hệ thống tự truyền $object là Post Data (khi Sửa) hoặc null (khi Thêm mới).
*/
public static function render($object): void
{
// Lấy Metadata đã lưu cũ từ DB (Nếu đang ở trang Sửa). Còn Thêm mới sẽ rỗng = ''
$source_name = Metadata::get('post', $object->id, '_source_name', '');
$source_url = Metadata::get('post', $object->id, '_source_url', '');

// Sử dụng SkillDo Form Builder để in HTML chuẩn
$form = new Form();

echo $form->text('source_name', [
'label' => 'Tên Tạp chí/Báo gốc',
'value' => $source_name,
'placeholder' => 'VD: VNExpress'
]);

echo $form->url('source_url', [
'label' => 'Đường dẫn link báo gốc',
'value' => $source_url
]);
}

/**
* Lưu dữ liệu khi người dùng nhấn Lưu bài viết.
* Được gọi qua add_action('save_post_object', ...) từ bootstrap.
*
* Hook save thực tế (xem FormAdminHelper):
* - save_{module}_object : cả thêm mới lẫn cập nhật → ($id, $request, $insertData, $dataOutside)
* - save_{module}_object_add : chỉ khi thêm mới
* - save_{module}_object_edit : chỉ khi cập nhật
* - save_object : tất cả module → ($id, $module, $request, $insertData, $dataOutside)
*
* @param int $post_id ID bài viết vừa lưu
* @param Request $request HTTP Request chứa dữ liệu form
* @param array $insertData Dữ liệu đã được insert vào DB
* @param array $dataOutside Dữ liệu nằm ngoài model (meta, file...)
*/
public static function save(int $post_id, Request $request, array $insertData, array $dataOutside): void
{
if ($request->has('source_name')) {
Metadata::update('post', $post_id, '_source_name', $request->input('source_name'));
Metadata::update('post', $post_id, '_source_url', $request->input('source_url'));
}
}
}

4. Bước 2 – Đăng Ký vào Hệ Thống tại theme-child/bootstrap/theme-child.php

<?php
use Theme\Custom\PostSourceMetabox;

// Đăng ký metabox (hiển thị form phụ trong trang tạo/sửa bài viết)
add_action('add_meta_box', [PostSourceMetabox::class, 'register']);

// Lắng nghe sự kiện lưu bài viết để lưu metadata (cả thêm mới lẫn cập nhật)
// Hook nhận 4 tham số: $id, $request, $insertData, $dataOutside
add_action('save_post_object', [PostSourceMetabox::class, 'save'], 10, 4);

5. Truy Xuất Metadata Ra Màn Hình Frontend

Trong file View Theme theme-store/views/post-detail.blade.php:

@php
// SkillDo Blade đã bơm tự động Object bài viết là biến $post
$name = Metadata::get('post', $post->id, '_source_name', null);
$url = Metadata::get('post', $post->id, '_source_url', null);
@endphp

@if($name && $url)
<div class="source-credit" style="padding:10px; background:#f0f0f0;">
<p><strong>Bản quyền thuộc về:</strong> <a href="{{ $url }}" target="_blank">{{ $name }}</a></p>
</div>
@endif

TỔNG KẾT

BướcFileViệc cần làm
1theme-child/app/Custom/PostSourceMetabox.phpTạo class chứa register(), render(), save()
2theme-child/bootstrap/theme-child.phpĐăng ký 2 action: add_meta_boxsave_post_object
3View blade frontendDùng Metadata::get() để hiển thị ra giao diện người dùng

Lưu ý quan trọng:

  1. Lợi dụng khả năng mở rộng không giới hạn của bảng Metadata CMS (Gồm Module Type, Target ID, Key, và Value).
  2. Dùng Metabox Hook để mượn chỗ đặt form thu thập liệu mà không phải phá hư form Mặc Định CMS.
  3. Không làm bốc hơi/phình to Hệ Quản Trị Hệ Cơ Sở Dữ Liệu SQL cốt lõi của bảng chính bằng việc hạn chế dùng chức năng Thêm Cột (Col).
  4. Phân chia rõ ràng (Tên trường bắt đầu bằng gạch dưới _ là Metabox Ẩn ở UI, không gạch là Custom Field mặc định cho Admin).